package com.itheima.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.itheima.dao.MenuDao;
import com.itheima.dao.PermissionDao;
import com.itheima.dao.RoleDao;
import com.itheima.dao.UserDao;
import com.itheima.entity.PageResult;
import com.itheima.exceptions.BusinessException;
import com.itheima.pojo.Menu;
import com.itheima.pojo.Role;
import com.itheima.pojo.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author W.J.Y
 */
@Service(version = "1.0.0", interfaceClass = UserService.class)
@Transactional
public class UserServiceImpl implements UserService {

    @Resource
    private UserDao userDao;

    @Resource
    private RoleDao roleDao;

    @Resource
    private PermissionDao permissionDao;

    @Resource
    private MenuDao menuDao;

    /**
     * 根据用户名查询用户信息（包含角色权限等）
     *
     * @param username 用户名
     * @return 用户实例
     */
    @Override
    public User findUserByUserName(String username) {
        //根据用户名查询用户信息
        User user = userDao.findUserByUserName(username);
        //根据用户ID查询用户拥有角色
        user.setRoles(roleDao.findRolesByUserId(user.getId()));
        //遍历角色并查询角色拥有权限
        Set<Role> roles = user.getRoles();
        for (Role role : roles) {
            role.setPermissions(permissionDao.findPermissionsByRoleId(role.getId()));
        }
        return user;
    }

    /**
     * 新增用户
     *
     * @param user 用户实例
     * @throws BusinessException 可能出现的业务异常
     */
    @Override
    public void add(User user) throws BusinessException {
        Integer count = userDao.findByNameOrPhone(user);
        if (count > 0) {
            throw new BusinessException("已存在相同姓名、用户名或电话的用户，添加失败！");
        }
        String password = new BCryptPasswordEncoder().encode("123456");
        user.setPassword(password);
        user.setCreateTime(new Date());
        //首先首先添加用户
        userDao.add(user);
        //再添加用户与角色的关联
        Integer id = user.getId();
        Set<Integer> roleIds = user.getRoleIds();
        if (roleIds != null) {
            for (Integer roleId : roleIds) {
                userDao.setUserAndRole(id, roleId);
            }
        }
    }

    /**
     * 编辑用户
     *
     * @param user 用户实例
     * @throws BusinessException 可能出现的业务异常
     */
    @Override
    public void update(User user) throws BusinessException {
        Integer count = userDao.findByNameOrPhone(user);
        if (count > 0) {
            throw new BusinessException("已存在相同姓名或电话的用户，编辑失败！");
        }
        userDao.update(user);
        //首先删除用户与角色旧的关联关系
        userDao.deleteRoleSByUserId(user.getId());
        //再添加用户与角色的关联关系
        //再添加用户与角色的关联
        Integer id = user.getId();
        Set<Integer> roleIds = user.getRoleIds();
        if (roleIds != null) {
            for (Integer roleId : roleIds) {
                userDao.setUserAndRole(id, roleId);
            }
        }
    }

    /**
     * 查找全部用户数据
     *
     * @return 全部用户
     */
    @Override
    public List<User> findAll() {
        return userDao.findAll();
    }

    /**
     * 删除用户
     *
     * @param id 用户ID
     * @throws BusinessException 可能出现的业务异常
     */
    @Override
    public void delete(int id) throws BusinessException {
        //TODO 检查用户是否在别的地方被使用了

        userDao.delete(id);
    }

    /**
     * 分页查询用户信息
     *
     * @param pageNum     当前页
     * @param pageSize    每页显示条数
     * @param queryString 查询语句
     * @return 用户分页信息
     */
    @Override
    public PageResult findPage(int pageNum, int pageSize, String queryString) {
        //开启分页查询
        PageHelper.startPage(pageNum, pageSize);
        //调用dao层查询语句
        Page<User> page = userDao.findPage(queryString);
        List<User> result = page.getResult();
        for (User user : result) {
            Set<Role> roles = roleDao.findRolesByUserId(user.getId());
            user.setRoles(roles);
        }
        System.out.println(page.getResult());
        //封装分页查询结果对象
        return new PageResult(page.getTotal(), page.getResult());
    }

    /**
     * 根据ID查询用户
     *
     * @param id 用户ID
     * @return 用户实例
     */
    @Override
    public User findById(int id) {
        User user = userDao.findById(id);
        Set<Integer> roleIds = userDao.findRoleIdsByUserId(id);
        user.setRoleIds(roleIds);
        return user;
    }

    /**
     * 更新用户登录次数
     *
     * @param user 用户数据
     */
    @Override
    public void updateLoginCount(User user) {
        userDao.updateLoginCount(user);
    }

    /**
     * 根据用户名查询菜单信息
     *
     * @param username 用户名
     * @return 菜单信息
     */
    @Override
    public List<Menu> findMenusByUserName(String username) {
        //定义用来存放菜单的集合,使用ID去重
        Set<Menu> menusFinal = new TreeSet<>(new Comparator<Menu>() {
            @Override
            public int compare(Menu o1, Menu o2) {
                int result = o1.getPriority() - o2.getPriority();
                result = result == 0 ? o1.getId() - o2.getId() : result;
                return result;
            }
        });
        //首先获取用户ID
        User user = this.findUserByUserName(username);
        int userId = user.getId();
        //根据用户ID查询用户拥有的角色
        Set<Role> rolds = roleDao.findRolesByUserId(userId);
        //遍历用户所拥有的角色获取用户拥有的所有菜单
        for (Role rold : rolds) {
            Integer roleId = rold.getId();
            LinkedHashSet<Menu> menus = menuDao.findMenuByRoleId(roleId);
            if (menus != null) {
                //遍历角色拥有的菜单并将一级菜单加入最终菜单结果
                for (Menu menu : menus) {
                    if (menu != null && menu.getLevel() == 1) {
                        //并且清除已有的子菜单
                        menu.setChildren(null);
                        menusFinal.add(menu);
                    }
                }
                //遍历最终菜单结果中的一级菜单并将拥有的菜单中的对应的子菜单放入其中
                for (Menu menu : menusFinal) {
                    //menu一级菜单、即父菜单
                    Integer parentId = menu.getId();
                    List<Menu> childrens = new ArrayList<>();
                    for (Menu menuChildren : menus) {
                        //menuChildren二级菜单、即一级菜单的子菜单
                        if (menuChildren!=null&&menuChildren.getParentMenuId()==parentId){
                            //二级菜单的父菜单ID等于一级菜单的ID，将该二级菜单放入一级菜单的子菜单集合
                            childrens.add(menuChildren);
                        }
                    }
                    //将子菜单集合赋值给父级菜单
                    menu.setChildren(childrens);
                }
            }
        }
        List<Menu> collect = menusFinal.stream().collect(Collectors.toList());
        return collect;
    }

    /**
     * 修改密码
     * @param password  修改后的密码
     */
    @Override
    public void changePassword(String password,String username) {
        String encodePwd = new BCryptPasswordEncoder().encode(password);
        userDao.changePassword(encodePwd,username);
    }
}
